import bpmLog from './log';
import { MESSAGE_TYPE } from './messageTypeEnum';
type FunctionType = (...args: any[]) => any;
interface IBpmOpenSdk {
  closeWindow: () => void;
  registerAction: (
    actionName: string,
    callback?: FunctionType | undefined,
  ) => any;
  destroy: () => void;
  postMessage: (message: any) => void;
  onProcessStatus: (callback: FunctionType) => void;
}

class BpmSdk implements IBpmOpenSdk {
  private events: { [eventName: string]: FunctionType[] } = {};
  // 被拦截的action, 如果没有被拦截，则需要回传消息回去。
  private actions: string[] = [];

  // 表单数据
  private formData: any = {};

  // nameSpaceId
  private namespaceId: string = '';

  // 获取表单数据的初始化方法，方便实时获取
  public getFormData = (needValidate: boolean = false) => {
    bpmLog('表单需要是否必填校验', needValidate);
    return this.formData;
  };

  constructor() {
    this.events = {};
    bpmLog('BpmSdk 实例化');
    this.namespaceId = Date.now().toString();
    // 与BPM页面建立起监听
    window.parent.postMessage(
      {
        hasListener: true,
      },
      '*',
    );
    window.addEventListener('message', this.handleMessage.bind(this));
  }

  // 事件行为注册
  private on(eventName: string, callback: FunctionType): void {
    if (!this.events[eventName]) {
      this.events[eventName] = [];
    }

    this.events[eventName].push(callback);
  }

  // 事件销毁
  private off(eventName: string, callback?: FunctionType): void {
    if (this.events[eventName]) {
      if (callback) {
        const index = this.events[eventName].indexOf(callback);
        if (index !== -1) {
          this.events[eventName].splice(index, 1);
        }
      } else {
        delete this.events[eventName];
      }
    }
  }

  // 执行事件方法
  private executeCallbacks(event: MessageEvent): void {
    const eventName = event.data.messageType;
    this.events[eventName].forEach((callback) => {
      callback(event);
    });
  }

  // SDK销毁
  public destroy(): void {
    bpmLog('BPM SDK DESTROY');
    this.events = {};
    window.removeEventListener('message', this.handleMessage.bind(this));
  }

  // 校验流程事件是否合法
  validateMessage(event: MessageEvent): boolean {
    const messageType = event?.data?.messageType;
    if (!event.data || !messageType || !this.events[messageType]) {
      return false;
    }
    return true;
  }

  // 流程消息监听
  handleMessage(event: MessageEvent): void {
    const eventData = event?.data;
    const isActionType = eventData?.messageType === MESSAGE_TYPE.GET_FORM_DATA;
    const hasAction = this?.actions?.includes(eventData?.submitType);
    const shouldExecuteCallbacks = (isActionType && hasAction) || !isActionType;

    if (this.validateMessage(event) && shouldExecuteCallbacks) {
      bpmLog('BPM SDK MESSAGE VALID', event);
      this.executeCallbacks(event);
    } else if (isActionType && eventData?.submitType) {
      const formData = this.getFormData(eventData?.needValidate);
      const emitFn = this.emitAction;
      if (formData instanceof Promise) {
        formData.then((data) => {
          emitFn({
            ...eventData,
            formData: data,
            success: true,
          });
        });
      } else {
        bpmLog('BPM_SDK_EMIT_ACTION', eventData);
        emitFn({
          ...eventData,
          formData,
          success: true,
        });
      }
    }
  }

  // 发送消息
  public postMessage(message: any): void {
    window.parent.postMessage(
      { ...message, success: true },
      message?.url || '*',
    );
  }

  // 触发BPM流程操作，如查看流程
  public async emitAction(message: any): Promise<void> {
    bpmLog('BPM_SDK_EMIT_ACTION', message);
    let url = message?.url;
    let iframeId = message?.iframeId;
    if (!url) {
      const action: any = await this.getActionInfo('bpmCaseDto');
      url = action?.url;
      iframeId = action?.iframeId;
    }
    bpmLog('Action Params', {
      ...message,
      url,
      messageType: MESSAGE_TYPE.GET_FORM_DATA,
      success: true,
      iframeId,
    });
    window.parent.postMessage(
      {
        ...message,
        url,
        iframeId,
        messageType: MESSAGE_TYPE.GET_FORM_DATA,
        success: true,
      },
      url || '*',
    );
  }

  // 监听流程操作取消、选人选分支弹出、操作成功、失败的消息。
  public onProcessStatus(callback: FunctionType): void {
    const statusFn = (evt: MessageEvent) => {
      bpmLog('BPM_SDK_PROCESS_STATUS Listen', evt?.data);
      callback?.(evt?.data);
    };
    this.on(MESSAGE_TYPE.PROCESS_ACTION_SUCCESS, statusFn);
    this.on(MESSAGE_TYPE.PROCESS_ACTION_FAIL, statusFn);
    this.on(MESSAGE_TYPE.PROCESS_ACTION_POP, statusFn);
    this.on(MESSAGE_TYPE.PROCESS_ACTION_CANCEL, statusFn);
  }
  // 关闭父页面
  public closeWindow() {
    bpmLog('BPM_SDK CLOSE_WINDOW');
    window.parent.postMessage({ messageType: MESSAGE_TYPE.CLOSE_WINDOW }, '*');
  }

  // 具体的某一个操作行为事件
  public registerAction(actionName: string, callback?: FunctionType): any {
    this.actions = [...this.actions, actionName];
    bpmLog('BPM_SDK REGISTER ACTIONS ', actionName);
    const actionFn = (event: MessageEvent) => {
      const submitType = event?.data?.submitType;
      if (submitType === actionName) {
        bpmLog('BPM_SDK REGISTER ACTIONS EXECUTE', actionName, event.data);
        callback?.(event.data);
      }
    };
    this.on(MESSAGE_TYPE.GET_FORM_DATA, actionFn);
  }

  // 注册多个流程事件
  public registerMoreAction(
    actionNames: string[],
    callback?: FunctionType,
  ): any {
    this.actions = [...this.actions, ...actionNames];
    bpmLog('BPM_SDK REGISTER MORE ACTIONS ', actionNames);
    const actionFn = (event: MessageEvent) => {
      const submitType = event?.data?.submitType;
      if (actionNames.includes(submitType)) {
        bpmLog('BPM_SDK REGISTER MORE ACTIONS EXECUTE', submitType, event.data);
        callback?.(event.data);
      }
    };
    this.on(MESSAGE_TYPE.GET_FORM_DATA, actionFn);
  }

  public unregisterAction(actionName: string) {
    this.actions = this.actions.filter((item) => item !== actionName);
  }

  // 获取流程行为
  public getActionInfo(actionName: string, callback?: FunctionType) {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const that = this;
    that.postMessage({
      messageType: MESSAGE_TYPE.GET_ACTION_INFO,
      submitType: actionName,
      success: true,
    });

    return new Promise((resolve) => {
      that.on(MESSAGE_TYPE.GET_ACTION_INFO, (event: MessageEvent) => {
        if (event.data?.submitType === actionName) {
          bpmLog('===============BPM_SDK GET ACTION ===========', event?.data);
          callback?.(event?.data);
          resolve(event?.data);
        }
      });
    });
  }

  // 设置表单数据，传递方法或表单数据
  setFormData(cb: any) {
    if (typeof cb === 'function') {
      this.getFormData = cb;
    } else {
      this.formData = cb;
    }
  }

  // 获取BPM SDK 暴露的 API能力
  public getApi() {
    const openApi = {
      closeWindow: this.closeWindow,
      registerAction: this.registerAction.bind(this),
      destroy: this.destroy.bind(this),
      postMessage: this.postMessage.bind(this),
      onProcessStatus: this.onProcessStatus.bind(this),
      registerMoreAction: this.registerMoreAction.bind(this),
      setFormData: this.setFormData.bind(this),
      getFormData: this.getFormData.bind(this),
      emitAction: this.emitAction.bind(this),
      getActionInfo: this.getActionInfo.bind(this),
    };
    return openApi;
  }
}

export default BpmSdk;
